package com.ld.control.business.process.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ld.control.business.equipment.mapper.EquipmentMethodTmpMapper;
import com.ld.control.business.equipment.model.EquipmentHolePositionConvertModel;
import com.ld.control.business.equipment.model.EquipmentMethodTmpModel;
import com.ld.control.business.equipment.service.EquipmentHolePositionConvertService;
import com.ld.control.business.equipment.service.EquipmentService;
import com.ld.control.business.equipment.vo.external.EquipmentCommandSendParamReqVo;
import com.ld.control.business.equipment.vo.resp.EquipmentRespVo;
import com.ld.control.business.equipment.vo.resp.MethodRespVo;
import com.ld.control.business.external.vo.req.CallBackReqVo;
import com.ld.control.business.process.mapper.ProcessNodeExampleMapper;
import com.ld.control.business.process.mapper.ProcessNodeExampleRunningMapper;
import com.ld.control.business.process.mapper.ProcessNodeExampleRunningParamMapper;
import com.ld.control.business.process.mapper.ProcessNodeParamExampleMapper;
import com.ld.control.business.process.model.*;
import com.ld.control.business.process.service.ProcessExampleService;
import com.ld.control.business.process.service.ProcessNodeExampleRunningService;
import com.ld.control.business.process.service.ProcessNodeExampleService;
import com.ld.control.business.process.service.ProcessNodeParamExampleService;
import com.ld.control.business.process.vo.resp.ProcessNodeExampleRunningRecordResp;
import com.ld.control.business.record.model.ErrorNoticeRecordModel;
import com.ld.control.business.record.service.ErrorNoticeRecordService;
import com.ld.control.business.variable.model.VariableExampleModel;
import com.ld.control.business.variable.service.VariableExampleService;
import com.ld.control.business.variable.vo.resp.VariableExampleValueResp;
import com.ld.control.common.vo.EquipmentSystemMethodVo;
import com.ld.control.sysenum.*;
import com.ld.control.utils.CommonUtils;
import com.ld.control.utils.EquipmentCommandSendUtils;
import com.ld.control.utils.EquipmentSystemMethodUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 任务节点指令发送信息表 服务实现类
 * </p>
 *
 * @author wangfeng
 * @since 2024-05-27
 */
@Slf4j
@Service
public class ProcessNodeExampleRunningServiceImpl extends ServiceImpl<ProcessNodeExampleRunningMapper, ProcessNodeExampleRunningModel> implements ProcessNodeExampleRunningService {

    @Autowired
    private EquipmentMethodTmpMapper equipmentMethodTmpMapper;

    @Autowired
    private ProcessExampleService processExampleService;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private ProcessNodeExampleMapper processNodeExampleMapper;

    @Autowired
    private ProcessNodeParamExampleMapper processNodeParamExampleMapper;

    @Autowired
    private EquipmentCommandSendUtils equipmentCommandSendUtils;

    @Autowired
    private ProcessNodeExampleRunningMapper processNodeExampleRunningMapper;

    @Autowired
    private ErrorNoticeRecordService errorNoticeRecordService;

    @Autowired
    private ProcessNodeExampleService processNodeExampleService;

    @Autowired
    private ProcessNodeExampleRunningParamMapper processNodeExampleRunningParamMapper;

    @Autowired
    private EquipmentSystemMethodUtils equipmentSystemMethodUtils;

    @Autowired
    private VariableExampleService variableExampleService;

    @Autowired
    private ProcessNodeParamExampleService processNodeParamExampleService;

    @Autowired
    private EquipmentHolePositionConvertService equipmentHolePositionConvertService;

    @Override
    public ProcessNodeExampleRunningModel add(Long processNodeExampleId) {
        // 查询此节点的设备信息
        ProcessNodeExampleModel processNodeExampleModel = processNodeExampleMapper.selectById(processNodeExampleId);
        ProcessNodeExampleRunningModel processNodeExampleRunningModel = getProcessNodeExampleRunningModel(processNodeExampleModel);
        processNodeExampleRunningMapper.insert(processNodeExampleRunningModel);
        Long processNodeExampleRunningId = processNodeExampleRunningModel.getId();

        // 查询设备的方法类型是设备方法还是系统内部方法，如果是内部方法则需要通过内部方法名和参数名映射出设备真实的方法名称和参数名称
        EquipmentMethodTmpModel equipmentMethodTmpModel = equipmentMethodTmpMapper.selectById(processNodeExampleModel.getEquipmentMethodTmpId());
        // 查询节点参数信息
        QueryWrapper<ProcessNodeParamExampleModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ProcessNodeParamExampleModel.PROCESS_NODE_EXAMPLE_ID, processNodeExampleId);
        queryWrapper.eq(ProcessNodeParamExampleModel.USE_TYPE, 0);
        List<ProcessNodeParamExampleModel> processNodeParamExampleModelList = processNodeParamExampleMapper.selectList(queryWrapper);

        // 方法类型
        Integer methodType = equipmentMethodTmpModel.getMethodType();
        log.info("methodType:{}", methodType);
        // 0设备方法
        if (methodType == 0) {
            for (ProcessNodeParamExampleModel data : processNodeParamExampleModelList) {
                ProcessNodeExampleRunningParamModel processNodeExampleRunningParamModel = new ProcessNodeExampleRunningParamModel();
                processNodeExampleRunningParamModel.setProcessNodeExampleRunningId(processNodeExampleRunningId);
                processNodeExampleRunningParamModel.setSendMethodParamName(data.getName());
                processNodeExampleRunningParamModel.setSendMethodParamValue(data.getValue());
                processNodeExampleRunningParamModel.setParamType(data.getParamType());
                addProcessNodeExampleRunningParam(processNodeExampleModel, processNodeExampleRunningParamModel);
            }
        }
        // 1系统内部方法
        if (methodType == 1) {
            EquipmentSystemMethodVo equipmentSystemMethodVo = equipmentSystemMethodUtils.equipmentSystemMethodMapping(processNodeExampleRunningId, processNodeExampleModel, processNodeParamExampleModelList);
            // 修改内部自定义方法名为真实方法名
            processNodeExampleRunningModel.setSendMethodName(equipmentSystemMethodVo.getEquipmentMethodName());
            processNodeExampleRunningMapper.updateById(processNodeExampleRunningModel);
            List<ProcessNodeExampleRunningParamModel> processNodeExampleRunningParamModelList = equipmentSystemMethodVo.getProcessNodeExampleRunningParamModelList();
            for (ProcessNodeExampleRunningParamModel data : processNodeExampleRunningParamModelList) {
                addProcessNodeExampleRunningParam(processNodeExampleModel, data);
            }
        }
        return processNodeExampleRunningModel;
    }

    // 生成Running实例
    private void addProcessNodeExampleRunningParam(ProcessNodeExampleModel processNodeExampleModel, ProcessNodeExampleRunningParamModel model) {
        String nodeName = processNodeExampleModel.getNodeName();
        String value = model.getSendMethodParamValue();
        String sendMethodParamName = model.getSendMethodParamName();
        Long processNodeExampleId = processNodeExampleModel.getId();
        // 如果value是@开头则需要去变量实例表查询变量的值
        if (value.startsWith("@")) {
            VariableExampleValueResp variableExampleModel = variableExampleService.getByNameExt(processNodeExampleId, value);
            value = variableExampleModel.getCurrentValue();
        }
        log.info("send value:{}", value);
        log.info("send sendMethodParamName:{}", sendMethodParamName);
        model.setSendMethodParamValue(value);
        //Rotate特殊方法处理
        if (nodeName.equals("Rotate") && sendMethodParamName.equals("position")) {
            log.info("\n进入到特殊方法处理nodeName：{}", nodeName);
            Map<Integer, EquipmentHolePositionConvertModel> map = equipmentHolePositionConvertService.getMap(processNodeExampleModel.getEquipmentId());
            if (map != null && map.get(Integer.valueOf(value)) != null) {
                EquipmentHolePositionConvertModel equipmentHolePositionConvertModel = map.get(Integer.valueOf(value));
                Integer mappingHolePosition = equipmentHolePositionConvertModel.getMappingHolePosition();
                model.setSendMethodParamValue(mappingHolePosition + "");
                log.info("\n映射结果为：{}->{}", value, mappingHolePosition);
            }
        }
        processNodeExampleRunningParamMapper.insert(model);
    }

    public MethodRespVo sendCommand(Long processNodeExampleRunningId) {
        EquipmentCommandSendParamReqVo equipmentCommandSendParamReqVo = new EquipmentCommandSendParamReqVo();
        ProcessNodeExampleRunningModel processNodeExampleRunningModel = processNodeExampleRunningMapper.selectById(processNodeExampleRunningId);
        Long processNodeExampleId = processNodeExampleRunningModel.getProcessNodeExampleId();
        Long equipmentId = processNodeExampleRunningModel.getEquipmentId();
        EquipmentRespVo equipmentRespVo = equipmentService.getById(equipmentId);

        equipmentCommandSendParamReqVo.setTaskProcessNodeExampleId(processNodeExampleId);
        equipmentCommandSendParamReqVo.setProcessNodeExampleRunningId(processNodeExampleRunningId);
        equipmentCommandSendParamReqVo.setEquipmentId(equipmentRespVo.getId());
        equipmentCommandSendParamReqVo.setMethodTmpId(processNodeExampleRunningModel.getEquipmentMethodTmpId());
        equipmentCommandSendParamReqVo.setEquipmentCode(equipmentRespVo.getCode());
        equipmentCommandSendParamReqVo.setMethodName(processNodeExampleRunningModel.getSendMethodName());
        equipmentCommandSendParamReqVo.setSendTime(System.currentTimeMillis());
        equipmentCommandSendParamReqVo.setMessageId("command_messageId_" + processNodeExampleId + "_" + equipmentRespVo.getCode() + "_" + processNodeExampleRunningModel.getSendMethodName());

        QueryWrapper<ProcessNodeExampleRunningParamModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ProcessNodeExampleRunningParamModel.PROCESS_NODE_EXAMPLE_RUNNING_ID, processNodeExampleRunningId);
        List<ProcessNodeExampleRunningParamModel> processNodeExampleRunningParamModelList = processNodeExampleRunningParamMapper.selectList(queryWrapper);
        JSONObject methodParam = new JSONObject();
        for (ProcessNodeExampleRunningParamModel data : processNodeExampleRunningParamModelList) {
            String methodParamName = data.getSendMethodParamName();
            String methodParamNameValue = data.getSendMethodParamValue();
            String paramType = data.getParamType();
            log.debug("methodParamName:{}", methodParamName);
            log.debug("methodParamNameValue:{}", methodParamNameValue);
            log.debug("paramType:{}", paramType);
            Object paramValue = CommonUtils.getParamValue(paramType, methodParamNameValue);
            log.debug("paramValue:{}", paramValue);
            methodParam.put(methodParamName, paramValue);
        }
        equipmentCommandSendParamReqVo.setMethodParams(methodParam);

        MethodRespVo methodRespVo = null;
        ProcessNodeExampleRunningModel processNodeExampleRunningModelUpdate = new ProcessNodeExampleRunningModel();
        processNodeExampleRunningModelUpdate.setId(processNodeExampleRunningId);
        ErrorNoticeRecordModel errorNoticeRecordModel = new ErrorNoticeRecordModel();
        errorNoticeRecordModel.setProcessNodeExampleRunningId(processNodeExampleRunningId);
        errorNoticeRecordModel.setStatus(ErrorNoticeRecordStatusEnum.UNPROCESSED.getStatus());
        try {
            // 发送命令给设备驱动
            long startTime = System.currentTimeMillis();
            String respStr = equipmentCommandSendUtils.sendEquipmentCommand(equipmentCommandSendParamReqVo);
            long endTime = System.currentTimeMillis();
            log.info("sendEquipmentCommand Time:{}毫秒", (endTime - startTime));
            methodRespVo = JSONObject.parseObject(respStr, MethodRespVo.class);
            String code = methodRespVo.getCode();
            if (code.equals("0")) {
                processNodeExampleRunningModelUpdate.setResponseTime(new Date());
                processNodeExampleRunningModelUpdate.setStatus(RunningStatusEnum.SEND_SUCCESS.getStatus());
                processNodeExampleRunningModelUpdate.setResponseResult(methodRespVo.getMessage());
            } else {
                processNodeExampleRunningModelUpdate.setStatus(RunningStatusEnum.SEND_FAIL.getStatus());
                processNodeExampleRunningModelUpdate.setResponseResult(methodRespVo.getEquipmentErrorMsg());
                // 需要记录错误日志
                errorNoticeRecordModel.setErrorMsg(methodRespVo.getEquipmentErrorMsg());
                errorNoticeRecordService.add(errorNoticeRecordModel);
                // 节点状态修改成错误
                processNodeExampleService.updateNodeStatus(processNodeExampleRunningModel.getProcessNodeExampleId(), TaskStatusEnum.ERROR.getStatus());
            }
        /*} catch (BusinessException businessException) {
            String code = businessException.getCode();
            log.info("消息进入重试队列！");
            if (code.equals(ResultResponseEnum.REQ_TIMEOUT.getCode())) {
                // TODO 将消息丢到重试队列
            } else {
                // 记录错误日志
                errorNoticeRecordModel.setErrorMsg(businessException.getMessage());
                errorNoticeRecordService.add(errorNoticeRecordModel);
                // 节点状态修改成错误
                processNodeExampleService.updateNodeStatus(processNodeExampleRunningModel.getProcessNodeExampleId(), TaskStatusEnum.ERROR.getStatus());
            }
            processNodeExampleRunningModelUpdate.setStatus(RunningStatusEnum.SEND_FAIL.getStatus());
            processNodeExampleRunningModelUpdate.setResponseResult(businessException.getMessage());*/
        } catch (Exception e) {
            log.error("send_command_error", e);
            processNodeExampleRunningModelUpdate.setStatus(RunningStatusEnum.SEND_FAIL.getStatus());
            processNodeExampleRunningModelUpdate.setResponseResult(e.getMessage());
            // 记录错误日志
            errorNoticeRecordModel.setErrorMsg(e.getMessage());
            errorNoticeRecordService.add(errorNoticeRecordModel);
            // 节点状态修改成错误
            processNodeExampleService.updateNodeStatus(processNodeExampleRunningModel.getProcessNodeExampleId(), TaskStatusEnum.ERROR.getStatus());
        }
        // 修改running的状态
        processNodeExampleRunningMapper.updateById(processNodeExampleRunningModelUpdate);
        return methodRespVo;
    }

    @Override
    public void runningCallBack(CallBackReqVo reqVo) {
        String reqVoJsonString = JSONObject.toJSONString(reqVo);
        log.info("\n=================回传信息到running===================\n{}", reqVoJsonString);
        Long processNodeExampleRunningId = reqVo.getSendCommandParams().getProcessNodeExampleRunningId();
        Object result = reqVo.getResult();
        String resultJsonString = JSONObject.toJSONString(result);
        ProcessNodeExampleRunningModel processNodeExampleRunningModel = new ProcessNodeExampleRunningModel();
        processNodeExampleRunningModel.setId(processNodeExampleRunningId);
        processNodeExampleRunningModel.setStatus(RunningStatusEnum.CALLBACK.getStatus());
        processNodeExampleRunningModel.setResponseResult(resultJsonString);
        processNodeExampleRunningModel.setCallBackTime(new Date());
        processNodeExampleRunningModel.setIntactResponseResult(reqVoJsonString);
        processNodeExampleRunningMapper.updateById(processNodeExampleRunningModel);
        // 如果绑定了返回参数则需要进行回传绑定
        respParamUpdate(reqVo);
    }

    @Override
    public IPage<ProcessNodeExampleRunningRecordResp> getPageListByCondition(Long taskExampleId, Long processExampleId,
                                                                             String taskExampleCode, String sendMethodName, Integer current, Integer size) {
        IPage<ProcessNodeExampleRunningRecordResp> iPage = new Page<>(current, size);
        return processNodeExampleRunningMapper.selectRecordPageListByCondition(iPage, taskExampleId, processExampleId, taskExampleCode, sendMethodName);
    }

    private ProcessNodeExampleRunningModel getProcessNodeExampleRunningModel(ProcessNodeExampleModel processNodeExampleModel) {
        ProcessExampleModel processExampleModel = processExampleService.getById(processNodeExampleModel.getProcessExampleId());
        ProcessNodeExampleRunningModel processNodeExampleRunningModel = new ProcessNodeExampleRunningModel();
        processNodeExampleRunningModel.setTaskExampleId(processExampleModel.getTaskExampleId());
        processNodeExampleRunningModel.setSubTaskExampleId(processExampleModel.getSubTaskExampleId());
        processNodeExampleRunningModel.setStatus(RunningStatusEnum.NOT_SEND.getStatus());
        processNodeExampleRunningModel.setProcessExampleId(processNodeExampleModel.getProcessExampleId());
        processNodeExampleRunningModel.setProcessNodeExampleId(processNodeExampleModel.getId());
        processNodeExampleRunningModel.setEquipmentMethodTmpId(processNodeExampleModel.getEquipmentMethodTmpId());
        processNodeExampleRunningModel.setEquipmentId(processNodeExampleModel.getEquipmentId());
        processNodeExampleRunningModel.setSendMethodName(processNodeExampleModel.getNodeName());
        processNodeExampleRunningModel.setSendTime(new Date());
        return processNodeExampleRunningModel;
    }

    private void respParamUpdate(CallBackReqVo reqVo) {
        log.info("开始处理resp参数");
        JSONObject result = reqVo.getResult();
        EquipmentCommandSendParamReqVo sendCommandParams = reqVo.getSendCommandParams();
        Long processNodeExampleId = sendCommandParams.getTaskProcessNodeExampleId();
        // 查询此节点下面所有返回参数
        Map<String, ProcessNodeParamExampleModel> processNodeParamMap = processNodeParamExampleService.getProcessNodeParam(processNodeExampleId);
        for (Map.Entry<String, ProcessNodeParamExampleModel> entry : processNodeParamMap.entrySet()) {
            ProcessNodeParamExampleModel value = entry.getValue();
            if (value.getUseType() == NodeParamUseTypeEnum.RESP.getType()) {
                String paramValue = value.getValue();
                String paramName = value.getName();
                log.info("返回参数paramName:{},paramValue:{}", paramName, paramValue);
                String resultString = result.getString(paramName);
                log.info("获取到的值:{}", resultString);
                if (paramValue.startsWith("@") && !ObjectUtils.isEmpty(resultString)) {
                    VariableExampleModel variableExampleModel = variableExampleService.getByName(processNodeExampleId, paramValue);
                    variableExampleService.setVariableValueById(variableExampleModel.getId(), resultString, false);
                }
            }
        }
    }
}
